package game.breeze.resource;

import game.breeze.constants.ActionType;
import game.breeze.constants.EventType;
import game.breeze.constants.MapItemType;
import game.breeze.math.Position;
import game.breeze.resource.action.MoveAction;
import game.breeze.resource.action.ParallelAction;
import game.breeze.resource.action.RotateAction;
import game.breeze.resource.action.SequenceAction;
import game.breeze.resource.event.ChangeGridEvent;
import game.breeze.resource.event.ChangeTargetEvent;
import game.breeze.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.math.NumberUtils;
import org.dom4j.Document;
import org.dom4j.Element;

public class GameMapDef extends GameObjectDef {
	private Map<Integer, GameAction> actions = new HashMap<Integer, GameAction>();
	private Map<Integer, GameEvent> events = new HashMap<Integer, GameEvent>();
	private int width;
	private int height;
	private int[][] grid;
	private int rows;
	private int cols;
	private int cellSize;
	// 怪物重生间隔时间(秒)
	private int monsterReborn = 10;
	public List<MapItemDef> items = new ArrayList<MapItemDef>();

	public GameMapDef(Document doc) {
		super(doc);

		org.dom4j.Element root = doc.getRootElement();
		this.width = NumberUtils.toInt(root.attributeValue("width"));
		height = NumberUtils.toInt(root.attributeValue("height"));

		List<?> event = root.selectNodes("//map/event");
		for (int eventIndex = 0; eventIndex < event.size(); eventIndex++) {
			Element item = (Element) event.get(eventIndex);
			EventType type = EventType.valueOf(item.attributeValue("type"));
			GameEvent ge = parseEvent(type, item);
			ge.setId(NumberUtils.toInt(item.attributeValue("id")));
			this.events.put(ge.getId(), ge);
		}

		List<?> actions = root.selectNodes("//map/action");
		for (int actionIndex = 0; actionIndex < actions.size(); actionIndex++) {
			Element item = (Element) actions.get(actionIndex);
			ActionType type = ActionType.valueOf(item.attributeValue("type"));
			GameAction action = null;
			if (type == ActionType.sequence || type == ActionType.parallel) {
				action = (type == ActionType.sequence) ? new SequenceAction() : new ParallelAction();
				String[] subaction = item.attributeValue("subt").split(",");
				for (String sa : subaction) {
					ActionType sat = ActionType.valueOf(sa);
					action.addAction(parseAction(sat, item));
				}
			} else {
				action = parseAction(type, item);
			}

			action.setId(NumberUtils.toInt(item.attributeValue("id")));

			String[] events = item.attributeValue("events").split(",");
			for (String e : events) {
				action.addEvent(this.events.get(NumberUtils.toInt(e)));
			}

			this.actions.put(action.getId(), action);
		}

		List<?> items = root.selectNodes("//map/item");
		for (int itemIndex = 0; itemIndex < items.size(); itemIndex++) {
			Element item = (Element) items.get(itemIndex);
			MapItemType type = MapItemType.valueOf(item.attributeValue("type"));
			MapItemDef mapItem = null;
			switch (type) {
			case npc:
				mapItem = new MapNpcDef();
				break;
			case build:
				mapItem = new MapItemDef();
				break;
			case monster:
				mapItem = new MapMonsterDef();
				((MapMonsterDef) mapItem).setMonster(NumberUtils.toInt(item.attributeValue("def")));
				String[] ps = item.attributeValue("ps").split(",");
				for (String p : ps) {
					String[] coordinate = p.split("\\.");
					((MapMonsterDef) mapItem).addMovePostion(new Position(NumberUtils.toInt(coordinate[0]), NumberUtils.toInt(coordinate[1])));
				}
				break;
			default:
				continue;
			}
			mapItem.setMapItemType(type);
			mapItem.setId(NumberUtils.toInt(item.attributeValue("id")));
			mapItem.setX(NumberUtils.toInt(item.attributeValue("x")));
			mapItem.setY(height - NumberUtils.toInt(item.attributeValue("y")) - 32);
			this.items.add(mapItem);
		}

		Element grid = (Element) root.selectSingleNode("//map/grid");
		cols = NumberUtils.toInt(grid.attributeValue("cols"));
		rows = NumberUtils.toInt(grid.attributeValue("rows"));
		cellSize = NumberUtils.toInt(grid.attributeValue("size"));

		List<?> moveableList = root.selectNodes("//map/grid/moveable");

		this.grid = new int[rows][cols];
		int index = 0;
		for (int row = moveableList.size() - 1; row >= 0; row--) {
			Element moveable = (Element) moveableList.get(row);
			this.grid[index] = StringUtils.toInteger(moveable.attributeValue("detail"), ",");
			// this.grid[index][this.grid[index].length - 1] = 0;
			StringUtils.replace(this.grid[index], this.grid[index].length - 3, this.grid[index].length);
			if (row <= 2) {
				// ArrayUtils.EMPTY_BOOLEAN_ARRAY
				StringUtils.replace(this.grid[index], 0, this.grid[index].length);// new
			}
			index++;
		}

		this.items = Collections.unmodifiableList(this.items);
	}

	/**
	 * @return the width
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * @param width
	 *            the width to set
	 */
	public void setWidth(int width) {
		this.width = width;
	}

	/**
	 * @return the height
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * @param height
	 *            the height to set
	 */
	public void setHeight(int height) {
		this.height = height;
	}

	/**
	 * @return the grid
	 */
	public int[][] getGrid() {
		return grid;
	}

	/**
	 * @param grid
	 *            the grid to set
	 */
	public void setGrid(int[][] grid) {
		this.grid = grid;
	}

	/**
	 * @return the rows
	 */
	public int getRows() {
		return rows;
	}

	/**
	 * @param rows
	 *            the rows to set
	 */
	public void setRows(int rows) {
		this.rows = rows;
	}

	/**
	 * @return the cols
	 */
	public int getCols() {
		return cols;
	}

	/**
	 * @param cols
	 *            the cols to set
	 */
	public void setCols(int cols) {
		this.cols = cols;
	}

	/**
	 * @return the cellSize
	 */
	public int getCellSize() {
		return cellSize;
	}

	/**
	 * @param cellSize
	 *            the cellSize to set
	 */
	public void setCellSize(int cellSize) {
		this.cellSize = cellSize;
	}

	/**
	 * @return the monsterReborn
	 */
	public int getMonsterReborn() {
		return monsterReborn;
	}

	private GameAction parseAction(ActionType type, Element e) {
		GameAction action = null;
		if (type == ActionType.move) {
			MoveAction ma = new MoveAction();
			String[] coordinate = e.attributeValue(type.name()).split(",");
			ma.setTo(new Position(NumberUtils.toInt(coordinate[0]), NumberUtils.toInt(coordinate[1])));
			action = ma;
		} else if (type == ActionType.rotate) {
			RotateAction ra = new RotateAction();
			ra.setRotate(NumberUtils.toInt(e.attributeValue(type.name())));
			action = ra;
		}
		return action;
	}

	private GameEvent parseEvent(EventType type, Element e) {
		GameEvent ev = null;
		if (type == EventType.changeGrid) {
			ChangeGridEvent cge = new ChangeGridEvent();
			cge.setFrom(NumberUtils.toInt(e.attributeValue("from")));
			cge.setTo(NumberUtils.toInt(e.attributeValue("to")));
			List<Position> grids = new ArrayList<Position>();
			cge.setGrids(grids);

			String[] grid = e.attributeValue("girds").split(",");
			for (String ps : grid) {
				if (StringUtils.isEmpty(ps)) {
					continue;
				}
				String[] p = ps.split("\\.");
				grids.add(new Position(NumberUtils.toInt(p[1]), NumberUtils.toInt(p[0])));
			}
			ev = cge;
		} else if (type == EventType.changeTarget) {
			ChangeTargetEvent cte = new ChangeTargetEvent();
			cte.setTarget(NumberUtils.toInt(e.attributeValue("target")));
			cte.setStatus(NumberUtils.toInt(e.attributeValue("status")));
			ev = cte;
		}
		return ev;
	}

	@Override
	public void dispose() {
		// TODO Auto-generated method stub
		// super.dispose();
		for (MapItemDef item : items) {
			item.dispose();
		}
		// disposePath();
		items.clear();
		items = null;
		grid = null;
	}
}
